前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
  • React专栏

    • React组合式开发实战

      • 前端开发的四个时代
      • 企业管理系统的前世今生
      • 可视化页面搭建工具
      • 实战篇 01:开发前准备
      • 实战篇 02:项目脚手架
      • 实战篇 03:页面布局方案
      • 实战篇 04:权限管理机制
      • 实战篇 05:菜单匹配逻辑
      • 实战篇 06:消息通知设计
      • 实战篇 07:多语言支持
      • 继往开来:可视化页面搭建工具
    • React Hooks与Immutable实战

    • React SSR服务端渲染与同构实践

    • IM聊天系统前端开发实践

    • 微前端开发实战

    • React进阶实践

  • Vue专栏

  • 移动端专栏

  • Node专栏

  • 前端工程化专栏

  • 算法专栏

  • Typescript专栏

  • 其他专栏

完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

当我们使用各种技巧以充分爆发 Service Worker 的小宇宙时,往往因忽略其自身的更新问题,从而造成各种意想不到的故障。基于此,本章我们将目光重新回到 Service Worker 上,来聊一聊它的更新处理。

# Service Worker 脚本命名

现代前端构建体系中,输出的静态资源(脚本、图片、样式等)都以 [name].[hash].[ext] 的格式命名(比如:index.54a427d9cf.js),这是因为此类文件内容变更的频率非常低,我们可以对其使用强制缓存来避免不必要的网络请求,并且在文件变更之后,能够在页面刷新时得到更新。那么这种成为业界标准的命名是否适用于 Service Worker 脚本呢?我们通过一个例子进行说明:

  • 假设我们在 index.html 中注册了某版本的 Service Worker(文件名为:sw.v1.js),并通过预缓存将 index.html 添加到缓存中。
  • 当 Service Worker 更新后,index.html 需要注册新版本的 Service Worker(文件名为:sw.v2.js),
  • 如果我们使用缓存优先或仅缓存策略来响应 index.html 请求,除非用户手动清除缓存,否则从缓存中得到的 index.html 中注册的 Service Worker 依旧为 sw.v1.js,sw.v2.js 将永久不会生效。

正是由于以上所述缘由,当我们处理 Service Worker 脚本时,一定要保证不同版本的文件名保持一致。

# Service Worker 脚本缓存

如果已存在一个版本的 Service Worker,那么再次触发其安装的条件是从服务器获取的 sw.js 与本地版本存在差异。如果我们对 sw.js 进行缓存,除非用户手动清除缓存或缓存失效,否则新版本的 Service Worker 将永远无法安装。因此,不要对 Service Worker 脚本设置缓存(服务端可通过 max-age: 0 响应头来避免缓存)

# 慎用 skipWaiting

Service Worker 安装成功后,如果已存在一个版本的 Service Worker 且有页面尚未关闭,新版 Service Worker 便会进入等待状态,直到运行旧版本的页面全部关闭或在 install 事件中调用 skipWaiting 方法,新的版本才会进入激活状态。虽然我们可以通过调用 skipWaiting 方法让新版本尽快接管页面控制权,但这种过早的权利交接很可能造成一些意想不到的问题,比如:

假设 Service Worker 对请求 /users/tom 的响应进行了转换,在旧版本中返回的格式为:

{
  name: 'Tom',
  city: 'NanJing'
}
@前端进阶之旅: 代码已经复制到剪贴板

新版本中返回的格式为:

{
  v2Name: 'Tom',
  v2City: 'NanJing'
}
@前端进阶之旅: 代码已经复制到剪贴板

这样的不一致可能在某些情况下导致应用崩溃且难以复现,这就等于在应用中埋藏了一个不稳定的定时炸弹,所以,除非能够保证同一个页面在两个版本相继处理的情况下依旧能够正常工作,否则尽量避免使用 skipWaiting 方法

# 处理更新的正确姿势

上文说到滥用 skipWaiting 可能会带来意想不到的问题,那如果我们想要新版本的 Service Worker 尽快接收控制权,又该如何处理呢?我的建议是将控制权交给用户,比如:

上图中,当新版本的 Service Worker 安装成功后,给予用户提示,并让用户自行决定是否进行更新,如果用户确定更新,我们便激活新版本,并在激活成功后给予提示并刷新页面(如下图)。

更新提示显示时机代码实现:

export async function initSW() {
  if ('serviceWorker' in navigator) {
    const registration = await navigator.serviceWorker.register('/sw.js');
    //... 其他逻辑
    if (registration.waiting) {
      showSwUpdateTip(registration);
    }
    registration.addEventListener(
fe
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
  • React专栏

    • React组合式开发实战

      • 前端开发的四个时代
      • 企业管理系统的前世今生
      • 可视化页面搭建工具
      • 实战篇 01:开发前准备
      • 实战篇 02:项目脚手架
      • 实战篇 03:页面布局方案
      • 实战篇 04:权限管理机制
      • 实战篇 05:菜单匹配逻辑
      • 实战篇 06:消息通知设计
      • 实战篇 07:多语言支持
      • 继往开来:可视化页面搭建工具
    • React Hooks与Immutable实战

    • React SSR服务端渲染与同构实践

    • IM聊天系统前端开发实践

    • 微前端开发实战

    • React进阶实践

  • Vue专栏

  • 移动端专栏

  • Node专栏

  • 前端工程化专栏

  • 算法专栏

  • Typescript专栏

  • 其他专栏